'''
Created on Jul 9, 2011

@author: Cihat Basol
'''

import sqlite3 as lite

from PyQt4.QtGui import *
from PyQt4 import QtCore
from PyQt4.QtCore import QObject, SIGNAL, QThread, pyqtSignal

from dexen.system.client import db
from dexen.system.common.states import JobState
from dexen.system.client.controller.db_syncher import DBSyncher
from dexen.system.client.ui.job_main import JobWidget
from dexen.system.client.proxy import ServerProxy, JobProxy
from dexen.system.client.ui.conn_widget import ConnectionWidget


class JobSyncher(QObject):
    
    server_info_initialized = pyqtSignal(list) # list of db.ServerInfo
    #connected = pyqtSignal(db.ServerInfo)
    #server_info_updated = pyqtSignal(db.ServerInfo)
    #actions_received = pyqtSignal(list) # list of Action
    
    def __init__(self):
        super(JobSyncher, self).__init__()
        self.svr_proxies = {} # (name, start_time) : ServerProxy
        self.cur_proxy = None # ServerProxy
        self.timer = None
    
    def _execute_query(self, query, params=None):
        conn = db.get_connection()
        assert isinstance(conn, lite.Connection)
        cursor = conn.cursor()
        assert isinstance(cursor, lite.Cursor)
        if params != None:
            cursor.execute(query, params)
        else:
            cursor.execute(query)
        res = cursor.fetchall()
        cursor.close()
        return res
    
    def on_started(self):
        self.db_syncher = DBSyncher()
                
        svr_info_list = self.db_syncher.get_server_info()
        
        for svr_info in svr_info_list:
            assert isinstance(svr_info, db.ServerInfo)
            svr_info.disconnect()
        
        # Emit signal
        self.server_info_initialized.emit(svr_info_list)

        # Retrieve actions from DB
        for svr_info in svr_info_list:
            assert isinstance(svr_info, db.ServerInfo)
            svr_proxy = self.get_proxy(svr_info.get_name(), 
                                       svr_info.get_start_time())
            assert isinstance(svr_proxy, ServerProxy)
            for job_id, job_info in svr_info.get_jobs().items():
                actions = self.db_syncher.get_actions(svr_info, job_id)
                # Process actions in the respective JobProxy
                job_proxy = svr_proxy.get_job_proxy(job_id)
                assert isinstance(job_proxy, JobProxy)
                job_proxy.process_actions(actions)
                
                # Emit signal
                self.emit(SIGNAL("actions_initialized"), job_info, actions)
                self.emit(SIGNAL("inds_initialized"), job_info, job_proxy.get_inds())

    
    def get_proxy(self, svr_name, start_time):
        if not self.svr_proxies.has_key((svr_name, start_time)):
            self.svr_proxies[(svr_name, start_time)] = ServerProxy()
        return self.svr_proxies[(svr_name, start_time)]
    
    def on_connected(self, svr_name, start_time):
        print "JobSyncher: on_connected to:", svr_name
        self.cur_proxy = self.get_proxy(svr_name, start_time)
    
        self.cur_proxy.connect(svr_name)
        self.server_info = db.ServerInfo()
        self.server_info.set_info(svr_name, start_time)
        
        # Persist to DB
        self.db_syncher.persist_server_info(self.server_info)
        self.svr_id = self.db_syncher.get_svr_id(self.server_info)
        
        # Start timer
        self.timer = QtCore.QTimer()
        # QThread.sleep(1)
        self.timer.start(2000)
        
        self.connect(self.timer, SIGNAL("timeout()"), self.do_synch)

    def do_synch(self):
        try:
            self.server_info.clear_jobs()
            job_states = self.cur_proxy.get_job_states()
            for job_state in job_states:
                assert isinstance(job_state, JobState)
                job_info = db.JobInfo(job_state)
                self.server_info.add_job(job_info)
            
            # Emit signal
            self.db_syncher.persist_jobs_info(self.server_info)
            self.emit(SIGNAL("server_info_updated"), self.server_info)
        except EOFError:
            self.on_disconnected()
        #except:
        #    print "Exception in JobSyncher:do_synch"
        #    self.timer.stop()
    
    def on_disconnected(self):
        print "JobSyncher: on_disconnected"
        self.timer.stop()
        #self.cur_proxy.disconnect()
        self.emit(SIGNAL("server_disconnected"), self.server_info)

    def on_get_actions(self, job_info):
        try:
            assert isinstance(job_info, db.JobInfo)
            job_id = job_info.get_id()
            job_proxy = self.cur_proxy.get_job_proxy(job_id)
            assert isinstance(job_proxy, JobProxy)
            # Retrieves new actions from the server since the last update
            job_proxy.refresh()
            actions = job_proxy.get_recent_actions()
            if len(actions) > 0:
                # Emit signal
                self.emit(SIGNAL("actions_received"), job_info, actions)
                self.emit(SIGNAL("inds_updated"), job_info, job_proxy.get_inds())
                self.db_syncher.persist_actions(self.server_info, job_id, actions)
        except EOFError:
            self.on_disconnected()
        #except:
        #    print "Exception in JobSyncher:on_get_actions"
        #    pass


class MainWidget(QWidget):
    def __init__(self):
        super(MainWidget, self).__init__()
        
        # Create the widgets
        self.conn_widget = ConnectionWidget()
        self.job_widget = JobWidget()
        
        # Configure the widgets
        self.job_widget.setEnabled(True)  
         
        # Layout the widgets
        layout = QVBoxLayout()
        layout.addWidget(self.conn_widget)
        layout.addWidget(self.job_widget)
        self.setLayout(layout)

        # Configure background thread with JobSyncher object        
        self.syncher = JobSyncher()
        self.bt = QThread()
        self.syncher.moveToThread(self.bt)

        # Configure the signal/slot connections
        self.connect(self.conn_widget, SIGNAL("connected"),
                     self.syncher.on_connected)
        self.connect(self.conn_widget, SIGNAL("disconnected()"),
                     self.syncher.on_disconnected)
        self.connect(self.bt, SIGNAL("started()"), self.syncher.on_started)
        self.connect(self.job_widget.get_navigator(), SIGNAL("refreshed"),
                     self.syncher.on_get_actions)
        self.connect(self.syncher, SIGNAL("server_info_updated"),
                     self.job_widget.on_server_info_updated)
        self.connect(self.syncher, SIGNAL("actions_received"), 
                     self.job_widget.on_actions_received)
        self.connect(self.syncher, SIGNAL("actions_initialized"),
                     self.job_widget.on_actions_initialized)
        self.connect(self.syncher, SIGNAL("server_disconnected"),
                     self.job_widget.on_server_disconnected)

        self.connect(self.syncher, SIGNAL("inds_initialized"),
                     self.job_widget.on_inds_initialized)
        self.connect(self.syncher, SIGNAL("inds_updated"),
                     self.job_widget.on_inds_updated)

        self.syncher.server_info_initialized.connect(
                self.job_widget.on_server_info_initialized)
        
        # Start background worker thread        
        self.bt.start()
        #print "Main thread", thread.get_ident()

    def on_server_connected(self):
        print "server connected"
        self.job_widget.on_server_connected()
    
    def on_server_disconnected(self):
        pass
    
    def on_server_info_initialized(self, server_info_list):
        pass
    
    def on_refresh(self):
        print "refresh is clicked"
        self.job_widget.on_job_refresh()

    def save_state(self):
        self.job_widget.save_state()

